//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using Microsoft.Research.ScientificWorkflow.TridentComposer;
using Microsoft.Research.ScientificWorkflow.TridentModel;
using Microsoft.Research.ScientificWorkflow.TridentUtilities;
using Microsoft.Research.DataLayer;
using TridentAPI;
using System.Windows.Controls.Primitives;
using System.ComponentModel;

namespace Microsoft.Research.ScientificWorkflow.UIDesigner
{
    /// <summary>
    /// Enum for the control mode.
    /// </summary>
    public enum ControlMode
    {
        /// <summary>
        /// The control is opened in editable mode.
        /// </summary>
        Edit,

        /// <summary>
        /// The control is opened in non-editable mode.
        /// </summary>
        ReadOnly
    }

    /// <summary>
    /// Interaction logic for PropertyListControl.xaml
    /// </summary>
    public partial class OutputPropertyListControl : UserControl, INotifyPropertyChanged
    {
        /// <summary>
        /// Current control Mode.
        /// </summary>
        private ControlMode currentControlMode;

        /// <summary>
        /// The composer control holding this element.
        /// </summary>
        private ComposerControl composerCtrl;

        /// <summary>
        /// Is Not Editable only instance.
        /// </summary>
        private bool isNotEditable;

        /// <summary>
        /// Is Editable only instance.
        /// </summary>
        private bool isEditable;

        /// <summary>
        /// Non user selection.
        /// </summary>
        private bool userSelection = true;

        /// <summary>
        /// Initialize a new instance of the property list.
        /// </summary>
        /// <param name="parameterDescriptionList">A collection of parameters.</param>
        public OutputPropertyListControl(Collection<ParameterDescriptionModel> parameterDescriptionList, ControlMode validationMode)
        {
            if (parameterDescriptionList == null)
            {
                throw new ArgumentNullException("parameterDescriptionList");
            }

            this.Loaded += (sender, e) => { this.GetComposerControl(); };
            this.OutputParameters = new ObservableCollection<ParameterDescriptionModel>(parameterDescriptionList);
            this.CurrentControlMode = validationMode;

            this.DataContext = this;
            InitializeComponent();
        }

        /// <summary>
        /// Initialize a new instance of the property list.
        /// </summary>
        public OutputPropertyListControl()
            : this( new ObservableCollection<ParameterDescriptionModel>(), ControlMode.ReadOnly)
        {
        }

        #region Public Properties
        /// <summary>
        /// Gets the parameters to be displayed in the property list.
        /// </summary>
        public ObservableCollection<ParameterDescriptionModel> OutputParameters { get; private set; }

       

        /// <summary>
        /// Gets or sets the current control mode.
        /// </summary>
        /// <value>The current control mode.</value>
        public ControlMode CurrentControlMode
        {
            get
            {
                return this.currentControlMode;
            }
            set
            {
                this.currentControlMode = value;
                this.IsNotEditable = this.currentControlMode == ControlMode.ReadOnly;
                this.IsEditable = this.currentControlMode == ControlMode.Edit;
                this.OnNotifyPropertyChanged("CurrentControlMode");
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether this instance is not editable.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is read only; otherwise, <c>false</c>.
        /// </value>
        public bool IsNotEditable
        {
            get
            {
                return this.isNotEditable;
            }
            set
            {
                this.isNotEditable = value;
                this.OnNotifyPropertyChanged("IsNotEditable");
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether this instance is not editable.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is read only; otherwise, <c>false</c>.
        /// </value>
        public bool IsEditable
        {
            get
            {
                return this.isEditable;
            }
            set
            {
                this.isEditable = value;
                this.OnNotifyPropertyChanged("IsEditable");
            }
        }

        #endregion

        #region Public methods
        /// <summary>
        /// Clears the list
        /// </summary>
        public void ClearList()
        {
            this.OutputParameters.Clear();
        }

        /// <summary>
        /// Update the property list.
        /// </summary>
        /// <param name="updatedCollection">The updated list of properties.</param>
        public void UpdateList(Collection<ParameterDescriptionModel> updatedCollection)
        {
            this.OutputParameters.Clear();

            foreach (ParameterDescriptionModel requiredModel in updatedCollection)
            {
                this.OutputParameters.Add(requiredModel);
            }
        }
        #endregion

        /// <summary>
        /// Handles the Checked event of the ToggleButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void ToggleButton_Checked(object sender, RoutedEventArgs e)
        {
            ToggleButton button = sender as ToggleButton;
            ListViewItem selectedListViewItem = this.outputPropertiesList.ContainerFromElement(button) as ListViewItem;

            // Find the border in the controltemplate of the listview and insert the joblist view into the border.
            ControlTemplate template = selectedListViewItem.Template;
            Border borderToInsert = template.FindName("descriptionHost", selectedListViewItem) as Border;

            borderToInsert.Visibility = Visibility.Visible;
        }

        /// <summary>
        /// Handles the Unchecked event of the ToggleButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void ToggleButton_Unchecked(object sender, RoutedEventArgs e)
        {
            ToggleButton button = sender as ToggleButton;
            ListViewItem selectedListViewItem = this.outputPropertiesList.ContainerFromElement(button) as ListViewItem;

            // Find the border in the controltemplate of the listview and insert the joblist view into the border.
            ControlTemplate template = selectedListViewItem.Template;
            Border borderToInsert = template.FindName("descriptionHost", selectedListViewItem) as Border;
            borderToInsert.Visibility = Visibility.Collapsed;
        }

        #region INotifyPropertyChanged Members

        /// <summary>
        /// Event for property change.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Raise property changed eventargs.
        /// </summary>
        /// <param name="changeProperty">Property anme.</param>
        private void OnNotifyPropertyChanged(string changeProperty)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(changeProperty));
            }
        }

        #endregion

        /// <summary>
        /// Handles the Initialized event of the ComboBox control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void ComboBox_Initialized(object sender, EventArgs e)
        {
            ComboBox comboBox = sender as ComboBox;

            ParameterDescriptionModel currentModel = comboBox.DataContext as ParameterDescriptionModel;

            if (currentModel != null)
            {
                this.userSelection = false;
                foreach (OutputType outputType in OutputSupportedTypesettingService.GetSupportedTypes(currentModel.DataType))
                {
                    comboBox.Items.Add(outputType.Name);
                }

                if (string.IsNullOrEmpty(currentModel.OutputType))
                {
                    comboBox.SelectedIndex = 0;
                }

                this.userSelection = true;
            }
        }

        /// <summary>
        /// Called when output text text changed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Controls.TextChangedEventArgs"/> instance containing the event data.</param>
        private void OnOutputTextTextChanged(object sender, TextChangedEventArgs e)
        {
            this.EnforceWorkflowSave();
        }

        /// <summary>
        /// Called when selection changed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Controls.SelectionChangedEventArgs"/> instance containing the event data.</param>
        private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (this.userSelection)
            {
                this.EnforceWorkflowSave();
            }
        }

        /// <summary>
        /// Get the composer control instance.
        /// </summary>
        private void GetComposerControl()
        {
            string composerCtrlName = (string)this.GetValue(ComposerControl.ComposerControlNameProperty);
            this.composerCtrl = Application.Current.MainWindow.FindName(composerCtrlName) as ComposerControl;
        }

        /// <summary>
        /// Enforces the workflow save.
        /// </summary>
        private void EnforceWorkflowSave()
        {
            if (this.composerCtrl != null)
            {
                this.composerCtrl.IsWFCommitted = false;
            }
        }
    }
}
